package com.shycloud.mido.common.util;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;
import java.util.*;

/**
 * @author Xiaoxing Yu
 * @date 2020/12/30 下午2:40
 **/
public class DateUtil {

	public static Map monthNameMap = new HashMap();

	static {
		monthNameMap.put(1, "JANUARY");
		monthNameMap.put(2, "FEBRUARY");
		monthNameMap.put(3, "MARCH");
		monthNameMap.put(4, "APRIL");
		monthNameMap.put(5, "MAY");
		monthNameMap.put(6, "JUNE");
		monthNameMap.put(7, "JULY");
		monthNameMap.put(8, "AUGUST");
		monthNameMap.put(9, "SEPTEMBER");
		monthNameMap.put(10, "OCTOBER");
		monthNameMap.put(11, "NOVEMBER");
		monthNameMap.put(12, "DECEMBER");
	}

	//LocalDateTime -> Date
	public static Date asDate(LocalDateTime localDateTime) {
		return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
	}

	//Date -> LocalDateTime
	public static LocalDateTime asLocalDateTime(Date date) {
		return Instant.ofEpochMilli(date.getTime()).atZone(ZoneId.systemDefault()).toLocalDateTime();
	}

	//Date -> LocalDate
	public static LocalDate asLocalDate(Date date) {
		return Instant.ofEpochMilli(date.getTime()).atZone(ZoneId.systemDefault()).toLocalDate();
	}

	//LocalDate -> Date
	public static Date asDate(LocalDate localDate) {
		return Date.from(localDate.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant());
	}

	public static LocalDateTime toLocalDateTime(Date date) {
		Instant instant = date.toInstant();
		ZoneId zoneId = ZoneId.systemDefault();

		return instant.atZone(zoneId).toLocalDateTime();
	}

	public static DayOfWeek getDayOfWeek(String dateStr, SimpleDateFormat format) throws Exception {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(format.parse(dateStr));
		//1-7 周日到周六
		int dayOfWeekIdx = calendar.get(Calendar.DAY_OF_WEEK);

		if (dayOfWeekIdx == 1) {
			return DayOfWeek.of(7);
		}

		//DayOfWeek 1-7 周一到周日
		return DayOfWeek.of(dayOfWeekIdx - 1);
	}

	public static List<LocalDate> getAllWeekDays(Integer yearNum, Integer monthNum, DayOfWeek dayOfWeekEnum) {
		Month month = Month.valueOf((String) monthNameMap.get(monthNum));
		List<LocalDate> result = new ArrayList<>();

//		LocalDate date = Year.now().atMonth(month).atDay(1).
		LocalDate date = Year.of(yearNum).atMonth(month).atDay(1).
				with(TemporalAdjusters.firstInMonth(dayOfWeekEnum));
		Month mi = date.getMonth();
		while (mi == month) {
			result.add(date);
			date = date.with(TemporalAdjusters.next(dayOfWeekEnum));
			mi = date.getMonth();
		}

		return result;
	}

	public static Date getFirstDayOfMonth(Integer monthOffset) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(new Date());
		calendar.add(Calendar.MONTH, monthOffset);
		int last = calendar.getMinimum(Calendar.DATE);
		calendar.set(Calendar.DAY_OF_MONTH, last);
		return calendar.getTime();
	}

	public static Date getFirstDayOfMonth(Integer year, Integer month) throws Exception {
		Calendar calendar = Calendar.getInstance();
		Date date = new SimpleDateFormat("yyyy-MM").parse(year + "-" + month);
		calendar.setTime(date);
		int last = calendar.getMinimum(Calendar.DATE);
		calendar.set(Calendar.DAY_OF_MONTH, last);
		return calendar.getTime();
	}

	public static Date addDays(Date date, Integer offset) throws Exception {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		calendar.add(Calendar.DAY_OF_MONTH, offset);
		return calendar.getTime();
	}

	/**
	 * 根据年 月 获取对应的月份 天数
	 */
	public static int getDaysByYearMonth(int year, int month) {
		Calendar a = Calendar.getInstance();
		a.set(Calendar.YEAR, year);
		a.set(Calendar.MONTH, month - 1);
		a.set(Calendar.DATE, 1);
		a.roll(Calendar.DATE, -1);
		int maxDate = a.get(Calendar.DATE);
		return maxDate;
	}

	public static Date getLastDayOfMonth(Integer monthOffset) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(new Date());
		calendar.add(Calendar.MONTH, monthOffset + 1);
		int min = calendar.getMinimum(Calendar.DATE);
		calendar.set(Calendar.DAY_OF_MONTH, min - 1);
		return calendar.getTime();
	}

	public static Integer getDaysDiff(Date date1, Date date2) {
		Instant inst1 = Instant.ofEpochMilli(date1.getTime());
		Instant inst2 = Instant.ofEpochMilli(date2.getTime());
		Long seconds = Duration.between(inst1, inst2).getSeconds();
		Long days = seconds / (24 * 60 * 60);

		return days.intValue();
	}

	public static Integer getTimestampMinDiff(Long end, Long start) {
		return new BigDecimal(Math.toIntExact(end - start))
				.divide(new BigDecimal(60000), BigDecimal.ROUND_HALF_UP).intValue();
	}

	public static Integer getTimestampMinDiffFloor(Long end, Long start) {
		return new BigDecimal(Math.toIntExact(end - start))
				.divide(new BigDecimal(60000), BigDecimal.ROUND_FLOOR).intValue();
	}

	public static Date toZero(Date date) {
		Calendar cal1 = Calendar.getInstance();
		cal1.setTime(date);
		// 将时分秒,毫秒域清零
		cal1.set(Calendar.HOUR_OF_DAY, 0);
		cal1.set(Calendar.MINUTE, 0);
		cal1.set(Calendar.SECOND, 0);
		cal1.set(Calendar.MILLISECOND, 0);
		return cal1.getTime();
	}

	public static LocalDate strToDate(String dateStr) {
		return LocalDate.parse(dateStr, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
	}

	public static LocalDateTime strToDateTime(String dateStr) {
		return LocalDateTime.parse(dateStr, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
	}

}
